#include "StdAfx.h"
#include "Clouds.h"
#include "Level.h"
#include "GraphCamera.h"
#include "PhysX.h"
#include "InputState.h"

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

Clouds::Clouds(Level *pLevel)
	:LevelElement()
	,m_pVertexLayout(0)
	,m_pVertexBuffer(0)
	,m_pDefaultEffect(0)	
	,m_pDefaultTechnique(0)	
	,m_pWorldVariable(0)
	,m_bReflection(false)
	,m_NumParticles(25)
{
	m_pLevel = pLevel;
}

Clouds::~Clouds(void)
{
	SafeRelease(m_pVertexBuffer );
	SafeRelease(m_pVertexLayout);
}
void Clouds::Initialize(ContentManager *pContentManager)
{
	m_pSpiteSheetTexture=		pContentManager->GetTexture(m_pLevel->GetDevice(), _T("./Textures/Spritesheet/CloudSpriteSheetOrg.dds"));

	m_BoundingBox.Min = D3DXVECTOR3(0, 0, 0);
	m_BoundingBox.Max = D3DXVECTOR3(2, 2, 2);

	CreateEffect(pContentManager);

	//Creating planes
	CreatePlanes();
	DefineInputlayout();
	BuildVertexBuffer();
	BuildIndexBuffer();
}
void Clouds::Tick(const InputState & refInputState)
{
	
}
void Clouds::Draw(const RenderContext* pRenderContext, Skydome::ScatteringInfo scatterinfo)
{
	if(!m_pDefaultTechnique )
	{
		MessageBox(0,_T("No Technique"),_T("ERROR"),0);
		return;
	}
	if(!m_pVertexBuffer)
	{
		MessageBox(0,_T("No Vertices"),_T("ERROR"),0);
		return;
	}	
	
	ResetWorldMatrix();
	D3DXVECTOR3 pos = pRenderContext->GetCamera()->GetPos();

	// Update Shader matrix variables
	D3DXMATRIX matView;

	if(!m_bReflection)
		matView = pRenderContext->GetCamera()->GetView();
	else
		matView = m_ReflectionViewMatrix;

	D3DXMATRIX matProj = pRenderContext->GetCamera()->GetProj();

	m_pWorldVariable->SetMatrix((float*)(m_World));
	m_pWVPVariable->SetMatrix((float*)(m_World*matView*matProj));

	m_pSunColorVariable->SetFloatVector((float*)D3DXVECTOR4(scatterinfo.SunColorAndIntensity.x,
		scatterinfo.SunColorAndIntensity.y,
		scatterinfo.SunColorAndIntensity.z, 100.0f));
	m_pEyePosVariable->SetFloatVector((float*)pos);

	m_pSpriteSheetVariable->SetResource(m_pSpiteSheetTexture);

	// Set the input layout
    m_pLevel->GetDevice()->IASetInputLayout( m_pVertexLayout );

	// Set vertex buffer(s)
	UINT offset = 0;
	UINT vertexBufferStride = sizeof(VertexCloud);
    m_pLevel->GetDevice()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &vertexBufferStride, &offset );
   	
	// Set index buffer
	m_pLevel->GetDevice()->IASetIndexBuffer(m_pIndexBuffer,DXGI_FORMAT_R32_UINT,0);

    // Set primitive topology
    m_pLevel->GetDevice()->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

    D3D10_TECHNIQUE_DESC techDesc;
    m_pDefaultTechnique->GetDesc( &techDesc );
    for( UINT p = 0; p < techDesc.Passes; ++p )
    {
        m_pDefaultTechnique->GetPassByIndex(p)->Apply(0);
		m_pLevel->GetDevice()->DrawIndexed( m_VecIndices.size(), 0, 0 ); 
    }
}

void Clouds::CreateEffect(ContentManager *pContentManager)
{
	m_pDefaultEffect = pContentManager->GetEffect(m_pLevel->GetDevice(),  _T("./Effect/Cloud.fx"));
	
	//get first technique found
	m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByName("Clouds");
	if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	GetEffectVariables(m_pDefaultEffect);
}

void Clouds::GetEffectVariables(ID3D10Effect* pEffect)
{
	//get effect variables
	m_pWorldVariable = pEffect->GetVariableByName("gWorld")->AsMatrix();
	m_pWVPVariable = pEffect->GetVariableByName("gWVP")->AsMatrix();
	
	m_pSpriteSheetVariable = pEffect->GetVariableByName("SpriteSheetTexture")->AsShaderResource();

	m_pSunColorVariable = pEffect->GetVariableByName("gSunColor")->AsVector();
	m_pEyePosVariable = pEffect->GetVariableByName("gEyePos")->AsVector();
}

void Clouds::DefineInputlayout()
{
	// Define the input layout DO NOT USE D3D10_APPEND_ALIGNED_ELEMENT 
	D3D10_INPUT_ELEMENT_DESC layout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	};
	UINT numElements = sizeof(layout)/sizeof(layout[0]);

    // Create the input layout
    D3D10_PASS_DESC PassDesc;
	// Get the pass decriptor from the effect technique
    m_pDefaultTechnique->GetPassByIndex( 0 )->GetDesc( &PassDesc );
    HR(m_pLevel->GetDevice()->CreateInputLayout( layout, numElements, PassDesc.pIAInputSignature, PassDesc.IAInputSignatureSize, &m_pVertexLayout ));

}

void Clouds::BuildVertexBuffer()
{
	//fill a buffer description to copy the vertexdata into graphics memory
	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexCloud ) * m_VecVertices.size();
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;

	D3D10_SUBRESOURCE_DATA initData;
	initData.pSysMem = m_VecVertices.data();
	//create a ID3D10Buffer in graphics memory containing the vertex info
	HR(m_pLevel->GetDevice()->CreateBuffer( &bd, &initData, &m_pVertexBuffer ));
}
void Clouds::BuildIndexBuffer()
{
	D3D10_BUFFER_DESC ibd;
    ibd.Usage = D3D10_USAGE_IMMUTABLE;
    ibd.ByteWidth = sizeof(DWORD) * m_VecIndices.size();
    ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
    ibd.CPUAccessFlags = 0;
    ibd.MiscFlags = 0;
    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = m_VecIndices.data();
    HR(m_pLevel->GetDevice()->CreateBuffer(&ibd, &initData, &m_pIndexBuffer));
}
void Clouds::DrawReflection(const RenderContext* pRenderContext, D3DXMATRIX reflectionviewmatrix, D3DXPLANE reflectionplane)
{
	m_bReflection = true;

	m_ReflectionViewMatrix = reflectionviewmatrix;
	//ID3D10EffectTechnique* PreviousTechnique = m_pDefaultTechnique;

	//m_pDefaultTechnique = m_pDefaultEffect->GetTechniqueByName("Reflection");
	//if(!m_pDefaultTechnique->IsValid())MessageBox(0,_T("Technique not valid"),_T("ERROR"),0);

	Draw(pRenderContext);

	//m_pDefaultTechnique = PreviousTechnique;
	m_bReflection = false;
}
void Clouds::CreatePlanes()
{
	for(int i = 0; i < m_NumParticles; ++i)
	{
		int index = i*4;
		//Bepalen van de positie
		//Bepalen van de scale
		//Bepalen van de texture
		float lengthx = m_BoundingBox.Max.x - m_BoundingBox.Min.x;
		float lengthy = m_BoundingBox.Max.y - m_BoundingBox.Min.y;
		float lengthz = m_BoundingBox.Max.z - m_BoundingBox.Min.z;

		float x = Lerp(m_BoundingBox.Min.x, m_BoundingBox.Max.x, (float)RandF(0, lengthx));
        float y = Lerp(m_BoundingBox.Min.y, m_BoundingBox.Max.y, (float)RandF(0, lengthy));
        float z = Lerp(m_BoundingBox.Min.z, m_BoundingBox.Max.z, (float)RandF(0, lengthz));

		float particleScale = D3DXVec3Length(&D3DXVECTOR3(m_BoundingBox.Max - m_BoundingBox.Min)) / 4.5f;

		int img = (int)((16 / m_BoundingBox.Max.y) * y);
		D3DXVECTOR4 extra = D3DXVECTOR4(((float)img) / 100.0f, particleScale, particleScale, 1.0f);

		float posu = img/4;
		float posv = posu - img;
		float umin = (posu-1) * (1.0f/4.0f);
		float vmin = (posv - 1) * (1.0f/4.0f);
		float umax = posu * (1.0f/4.0f);
		float vmax = posv * (1.0f/4.0f);

		VertexCloud v1;
		v1.pos = D3DXVECTOR3(x-2,y-2,z);
		v1.tex = D3DXVECTOR2(umin,vmax);//left bottom
		v1.extras = extra;
		m_VecVertices.push_back(v1);

		VertexCloud v2;
		v2.pos = D3DXVECTOR3(x-2,y + 2,z);
		v2.tex = D3DXVECTOR2(umin,vmin);//left top
		v2.extras = extra;
		m_VecVertices.push_back(v2);

		VertexCloud v3;
		v3.pos = D3DXVECTOR3(x+2,y+2,z);
		v3.tex = D3DXVECTOR2(umax,vmin);//righttop
		v3.extras = extra;
		m_VecVertices.push_back(v3);

		VertexCloud v4;
		v4.pos = D3DXVECTOR3(x+2,y-2,z);
		v4.tex = D3DXVECTOR2(umax,vmax);//right bottom
		v4.extras = extra;
		m_VecVertices.push_back(v4);

		m_VecIndices.push_back(index);
		m_VecIndices.push_back(index+1);
		m_VecIndices.push_back(index+2);

		m_VecIndices.push_back(index+2);
		m_VecIndices.push_back(index+3);
		m_VecIndices.push_back(index);
	}
}